package com.fywsy.fyweb.controller;

import com.fywsy.fyweb.entity.Cdk;
import com.fywsy.fyweb.entity.FormCdk;
import com.fywsy.fyweb.entity.Game;
import com.fywsy.fyweb.repository.CdkRepository;
import com.fywsy.fyweb.repository.GameRepository;
import com.fywsy.fyweb.utils.CdkUtils;
import com.fywsy.fyweb.utils.LocalDateTimeUtils;
import com.fywsy.fyweb.utils.TextUtils;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/cdk")
public class CdkController {

    public static final String PWD = "diyao88";

    @Autowired
    CdkRepository cdkRepository;

    @Autowired
    GameRepository gameRepository;



    /**
     * 创建指定游戏的cdk，
     * 可用设置
     *      有效期天数
     *      个数等
     * @param form
     * @return
     */
    @PostMapping("/create")
    @RateLimiter(name = "cdkLimit", fallbackMethod = "rateLimitFallback")
    public ResponseEntity<?> createCdk(@RequestBody FormCdk form) {
        if(form == null ||
                TextUtils.isEmpty(form.pwd) ||
                form.count == 0 ||
                form.validDay == 0)
            return ResponseEntity.badRequest().body("参数错误！");
        if(form.count > 100)
            return ResponseEntity.badRequest().body("最大100张！");
        if(!PWD.equals(form.pwd))
            return ResponseEntity.badRequest().body("密码错误！");

        if (!TextUtils.isEmpty(form.extract)) {
            //领取新的之前,先封禁老的!
            Cdk last = cdkRepository.findFirstByExtractAndBan(form.extract, false);
            if(last != null) {
                last.ban = true;
                cdkRepository.save(last);
            }
        }

        List<String> cdks = CdkUtils.createCdk(form.type, form.validDay,form.count);
        List<Cdk> collect = cdks.stream().map(i -> {
            Cdk cdk = new Cdk();
            cdk.gameId = form.gameId;
            cdk.validDay = form.validDay;
            cdk.type = form.type;
            cdk.code = i;
            if(!TextUtils.isEmpty(form.extract)) {
                cdk.extract = form.extract;
            }
            return cdk;
        }).collect(Collectors.toList());

        List<Cdk> result = cdkRepository.saveAll(collect);
        if(result.size() == 0) {
            return ResponseEntity.badRequest().body("数据库保存失败");
        }

        return ResponseEntity.ok(cdks);
    }


    /**
     * 使用cdk
     *
     * @return
     */
    @PostMapping("/use")
    @RateLimiter(name = "cdkLimit", fallbackMethod = "rateLimitFallback2")
    public String use(@RequestBody FormCdk form) {
        if(TextUtils.isEmpty(form.uid)) return "请输入UID";
        if(TextUtils.isEmpty(form.cdk)) return "请输入CDK";
        if(form.gameId == 0) return "请选择游戏后激活";

        Cdk cdk = cdkRepository.findFirstByCode(form.cdk.trim());
        if(cdk == null) return "无效的CDK";
        if (cdk.ban) return "封禁的CDK";
        if(cdk.type == 1) return useReusable(cdk, form);
        /**
         * 普通cdk使用逻辑：
         * 普通cdk是只能激活单个游戏，且激活之后无法改为其他游戏
         * 普通cdk又分为指定游戏和不指定游戏
         * 不指定的无法激活稀有游戏，稀有激活必须是指定游戏才可以，
         */
        if (cdk.used) return "该CDK已被" + cdk.uid + "使用";;

        Cdk cdkLast = cdkRepository.findFirstByGameIdAndUidOrderByUseTimeDesc(form.gameId, form.uid);
        if (cdkLast != null && !cdkLast.ban && !LocalDateTimeUtils.isOverGivenDays(cdkLast.useTime, cdkLast.validDay)) {
            return "有效期内，无需重复激活！请等过期后再使用";
        }

        Game game = gameRepository.findById(form.gameId).orElse(null);
        if(game == null) return "无此游戏！";
        if(cdk.gameId > 0) {//cdk是指定游戏的
            if(game.id != cdk.gameId) {
                Game game2 = gameRepository.findById(cdk.gameId).orElse(null);
                return "该CDK限[" + game2.name + "]使用";
            }
        }
        if(game.cate != 10 && cdk.gameId == 0) {//通用卡无法激活稀有游戏
            return "该CDK无法激活[" + game.name + "]";
        }

        cdk.used = true;
        cdk.useTime = LocalDateTime.now();
        cdk.uid = form.uid;
        if(cdk.gameId == 0) { //更新激活之后的gameId
            cdk.gameId = form.gameId;
        }
        cdkRepository.save(cdk);
        return "激活成功";

    }


    /**
     * 复用卡使用方法，
     * 复用卡是可以重复激活非稀有游戏的cdk
     * 复用卡主要用在：
     *  电商普通销售期限卡使用，避免频繁给卖家提供卡密，期限卡的话，只需要给玩家单个卡密就行了
     * @param cdk
     * @param form
     * @return
     */
    public String useReusable(Cdk cdk, FormCdk form) {
        // 验证cdk是否在有效期内
        if (cdk.useTime != null && LocalDateTimeUtils.isOverGivenDays(cdk.useTime, cdk.validDay)) {
            return "CDK已过有效期！";
        }

        Game game = gameRepository.findById(form.gameId).orElse(null);
        if(game == null) return "无此游戏！";
        if(game.cate != 10) {//复用卡无法激活稀有游戏
            return "该CDK无法激活[" + game.name + "]";
        }
        cdk.used = true;
        //复用卡不是第一次使用，则不更新useTime，因为useTime需要作为有效期的起始使用
        cdk.useTime = cdk.useTime == null ? LocalDateTime.now() : cdk.useTime;
        cdk.uid = form.uid;
        cdk.gameId = form.gameId;//把新的游戏id 更新到cdk上面
        cdkRepository.save(cdk);
        return "激活成功";
    }

    /**
     * 查询激活码的使用状态
     * @return
     */
    @PostMapping("/infos")
    public ResponseEntity<?> infos(@RequestBody List<Cdk> request) {
        if(request == null || request.size() == 0) return ResponseEntity.ok(new ArrayList<>());
        List<Long> ids = new ArrayList<>();
        List<String> uids = new ArrayList<>();
        request.forEach(i-> {
            ids.add(i.gameId);
            uids.add(i.uid);
        });
        LocalDate today = LocalDate.now();
        List<Cdk> cdks = cdkRepository.findLatestByGameIdsAndUids(ids, uids);
        cdks.forEach(cdk-> {
            LocalDateTime newExpiryDateTime = cdk.useTime.plusDays(cdk.validDay);
            LocalDate newExpiryDate = newExpiryDateTime.toLocalDate();
            cdk.useTime = newExpiryDateTime;
            if(cdk.ban) {
                cdk.status = "失效";
            } else if(newExpiryDate.isAfter(today)) {
                cdk.status = "有效";
            } else {
                cdk.status = "过期";
            }
        });
        return ResponseEntity.ok(cdks);
    }

    @GetMapping("/ban")
    public String ban(String account) {
        Cdk cdk = cdkRepository.findFirstByExtractAndBan(account, false);
        if(cdk != null) {
            cdk.ban = true;
            cdkRepository.save(cdk);
            return "OK";
        }
        return "未领取";
    }


    public ResponseEntity rateLimitFallback(Exception ex) {
        if(ex != null) System.out.println(ex.toString());
        return ResponseEntity.badRequest().body("操作太快，稍后重试~");
    }

    public String rateLimitFallback2(Exception ex) {
        if(ex != null) System.out.println(ex.toString());
        return "操作太快，稍后重试~";
    }


}
